--[[
	TotemGarden
	This addon shows a block of buttons that displays some common spells depending on
	the players class.
	This addon is written to mimic Saien's TotemBar. It does share some few lines of
	code but most code had to be rewritten to adjust this addon to work properly in
	the WoW 2.0 engine.

	Author: Rhidon @ Turalyon-EU
	Some functions contain leftover code from TotemBar, Author: Saien @ Hyjal
]]

TGApp = DongleStub("Dongle-1.1"):New("TotemGarden")


--------------------
-- Deprecated variables
-- These were used before a rewrite. They'll be removed asap.
local TotemGarden_Buttons = {}
local TotemGarden_Textures = {}
local TotemGarden_AssignedSpells = {}
TotemGarden_SpellList = {}
TotemGarden_SpellIDList = {}
TotemGarden_RunOnce = {}
TotemGarden_InCombat = nil
local TotemGarden
local TotemGardenTitleText
local TotemGardenHidden
local dongleDBDefautls = {
	profile = {
		mainframe = {
			scale = 1.0
		},
		hiddenframe = {
			height = 0,
			width = 0,
			r = 0.0, g = 0.0, b = 0.0,
			alpha = 0.2,
			connectv = "TOP",
			connecth = "LEFT",
		},
	},
	char = {},
	realm = {},
	class = {},
	faction = {},
	factionrealm = {},
	global = {},
}

--------------------

function TGApp:Initialize()
	self.version = "0.9.8"
	self.buttonsWide = 4
	self.buttonsHigh = 6
	self.buttons = {}
	self.textures = {}
	self.assignedSpells = {}
	self.spellList = {}
	self.spellIDList = {}
	self.runOnce = {}
	self.inCombat = nil

	self.db = self:InitializeDB("TotemGardenDongleDB", dongleDBDefautls)
	self.mainscale = self.db.profile.mainframe.scale or 1.0 -- TODO: kill this variable, it's kinda redundant to store it next to the db one.

	self.mainframe = nil
	self.mainframetitle = nil
	self.hiddenframe = nil
	self.sizetestbutton = nil

	-- Setup Slash commands
	self.cmd = self:InitializeSlashCommand("Totem Garden Slash Command", "TOTEMGARDEN", "tg", "totemgarden")
	self.cmd:RegisterSlashHandler("Toggles debugging.", "debug", "ToggleDebug")
	self.cmd:RegisterSlashHandler("'scale 1.0' Set scale of the TotemGarden window.", "scale (%d+\.?%d*)", "SetMainScale")
	self.cmd:RegisterSlashHandler("'hiddenalpha 0.2' Set transparency of the hidden window.", "hiddenalpha (%d+\.?%d*)", "SetHiddenAlpha")
	self.cmd:RegisterSlashHandler("'hiddenwidth 50' Set width of the hidden window. (0 for auto)", "hiddenwidth (%d+)", "SetHiddenWidth")
	self.cmd:RegisterSlashHandler("'hiddenheight 50' Set height of the hidden window. (0 for auto)", "hiddenheight (%d+)", "SetHiddenHeight")
	self.cmd:RegisterSlashHandler("'dockv top' Docks hidden window to the top or bottom edge of the main window. (top/bottom)", "dockv ([a-zA-Z]+)", "SetHiddenConnectVertical")
	self.cmd:RegisterSlashHandler("'dockh left' Docks hidden window to the left or right side of the main window. (left/right)", "dockh ([a-zA-Z]+)", "SetHiddenConnectHorizontal")
	

	self:RegisterEvent("PLAYER_REGEN_DISABLED", "CombatLockdown")
	self:RegisterEvent("PLAYER_REGEN_ENABLED", "CombatUnlock")



	self:CreateFrames()

	if GetBuildInfo() == "0.1.0" then
			self:Print("Using 0.1.0 methods")
	end
end

function TGApp:ToggleDebug()
	if self:IsDebugEnabled() then
		self:EnableDebug()
		self:Print("Debug mode disabled.")
	else
		self:EnableDebug(9)
		self:Print("Debug mode enabled.")
	end
end


function TGApp:SetMainScale(scalestring)
	local scale = tonumber(scalestring)
	self:Print(string.format("Setting scale to: %f", scale))
	self.mainscale = scale
	self.db.profile.mainframe.scale = scale
	self:ApplyMainScale()
end

function TGApp:SetHiddenAlpha(hastring)
	local halpha = tonumber(hastring)
	self:Print(string.format("Setting hidden alpha to: %f", halpha))
	self.db.profile.hiddenframe.alpha = halpha
	self.hiddenframe.bg:SetTexture(
		self.db.profile.hiddenframe.r,
		self.db.profile.hiddenframe.g,
		self.db.profile.hiddenframe.b,
		self.db.profile.hiddenframe.alpha)
end

function TGApp:SetHiddenWidth(hwstring)
	local hw = tonumber(hwstring)
	self:Print(string.format("Setting hidden width to: %d", hw))
	self.db.profile.hiddenframe.width = hw
	if hw == 0 then
		self.hiddenframe:SetWidth(self.mainframe:GetWidth())
	else
		self.hiddenframe:SetWidth(hw)
	end
end

function TGApp:SetHiddenHeight(hhstring)
	local hh = tonumber(hhstring)
	self:Print(string.format("Setting hidden height to: %d", hh))
	self.db.profile.hiddenframe.height = hh
	if hh == 0 then
		self.hiddenframe:SetHeight(self.mainframe:GetHeight())
	else
		self.hiddenframe:SetHeight(hh)
	end
end

function TGApp:SetHiddenConnectHorizontal(side)
	side = string.lower(side)
	if side == "left" then
		self.db.profile.hiddenframe.connecth = "LEFT"
	elseif side == "right" then
		self.db.profile.hiddenframe.connecth = "RIGHT"
	else
		self:Print(string.format("Unkown input: %s", side))
	end
	self:ApplyHiddenDock()
end

function TGApp:SetHiddenConnectVertical(side)
	side = string.lower(side)
	if side == "top" then
		self.db.profile.hiddenframe.connectv = "TOP"
	elseif side == "bottom" then
		self.db.profile.hiddenframe.connectv = "BOTTOM"
	else
		self:Print(string.format("Unkown input: %s", side))
	end
	self:ApplyHiddenDock()
end

function TGApp:ApplyHiddenDock()
	if not self.mainframe or not self.hiddenframe then
		return
	end
	
	local point = self.db.profile.hiddenframe.connectv .. self.db.profile.hiddenframe.connecth
	self.hiddenframe:ClearAllPoints()
	self.hiddenframe:SetPoint(point, self.mainframe, point)
end

function TGApp:ApplyMainScale()
	if (self.mainframe) then
		self.mainframe:SetScale(self.mainscale)
	end
end

function TGApp:Disable()
	self:UnregisterAllEvents()
end

function TGApp:CombatLockdown()
	self:Debug(3,"Entered combat lockdown.")
	self.inCombat = 1
end
function TGApp:CombatUnlock()
	self:Debug(3,"Left combat lockdown.")
	self.inCombat = nil
end

function TGApp:InCombat()
	if self.inCombat == 1 then
		return true
	else
		return false
	end
end

function TGSD(msg)
	-- NOTE: This function is DEPRECATED! Use self:Print() or self:PrintF() instead.
	msg = msg or ""
	--DEFAULT_CHAT_FRAME:AddMessage("TG: "..msg);
	TGApp:Print(msg)
end

-- This function contains some code from TotemBar by Saien
function TGApp:SetSpellList()
	local class = UnitClass("player");
	local race = UnitRace("player");
	local level = UnitLevel("player");

	if (class == "Shaman") then
		self.spellList = {
			-- Air
			"Nature Resistance Totem",
			"Windwall Totem",
			"Windfury Totem",
			"Grace of Air Totem",
			"Grounding Totem",
			"Tranquil Air Totem",
			-- Earth
			"Stoneclaw Totem",
			"Earthbind Totem",
			"Tremor Totem",
			"Strength of Earth Totem",
			"Stoneskin Totem",
			"Earth Elemental Totem",
			-- Water
			"Fire Resistance Totem",
			"Poison Cleansing Totem",
			"Disease Cleansing Totem",
			"Healing Stream Totem",
			"Mana Spring Totem",
			"Mana Tide Totem",
			-- Fire
			"Frost Resistance Totem",
			"Flametongue Totem",
			"Magma Totem",
			"Fire Nova Totem",
			"Searing Totem",
			"Fire Elemental Totem",
			-- Special Case (it's an air totem but not worth
			-- starting a new line)
			--"Sentry Totem",

		};
	elseif (class == "Warlock") then
		self.spellList = {
			-- Summons
			"Summon Imp",
			"Summon Voidwalker",
			"Summon Succubus",
			"Summon Felhunter",
			"Inferno",
			"Summon Felguard",
			-- Conjuring Items
			"Fel Armor",
			"Demon Armor",
			"Sense Demons",
			"Create Spellstone",
			"Create Firestone",
			"Create Soulstone",
			-- Curses - Bar 1
			"Curse of Doom",
			"Curse of Weakness",
			"Curse of Recklessness",
			"Curse of the Elements",
			"Unending Breath",
			"Detect Invisibility",
			-- Curses - Bar 2
			"Eye of Kilrogg",
			"Rain of Fire",
			"Hellfire",
			"Ritual of Souls",
			"Ritual of Summoning",
			"Ritual of Doom",
		};
		--[[
		-- Healthstones
		if (level >= 58) then
			self.spellList[7] = "Create Healthstone (Major)";
		elseif (level >= 46) then
			self.spellList[7] = "Create Healthstone (Greater)";
		elseif (level >= 34) then
			self.spellList[7] = "Create Healthstone";
		elseif (level >= 22) then
			self.spellList[7] = "Create Healthstone (Lesser)";
		end
		-- Soulstones
		if (level >= 60) then
			self.spellList[8] = "Create Soulstone (Major)";
		elseif (level >= 50) then
			self.spellList[8] = "Create Soulstone (Greater)";
		elseif (level >= 40) then
			self.spellList[8] = "Create Soulstone";
		elseif (level >= 30) then
			self.spellList[8] = "Create Soulstone (Lesser)";
		end
		-- Firestones
		if (level >= 56) then
			self.spellList[9] = "Create Firestone (Major)";
		elseif (level >= 46) then
			self.spellList[9] = "Create Firestone (Greater)";
		elseif (level >= 36) then
			self.spellList[9] = "Create Firestone";
		end
		-- Spellstones
		if (level >= 60) then
			self.spellList[10] = "Create Spellstone (Major)";
		elseif (level >= 48) then
			self.spellList[10] = "Create Spellstone (Greater)";
		end
		]]--
	elseif (class == "Mage") then
		self.spellList = {
			-- Teleports
			"Teleport: Undercity",
			"Teleport: Orgrimmar",
			"Teleport: Thunder Bluff",
			"Teleport: Silvermoon",
			"Teleport: Stonard",
			"Teleport: Shattrath",
			-- Portals
			"Portal: Undercity",
			"Portal: Orgrimmar",
			"Portal: Thunder Bluff",
			"Portal: Silvermoon",
			"Portal: Stonard",
			"Portal: Shattrath",
			-- Utility
			"Conjure Food",
			"Conjure Water",
			"Evocation",
			"Slow Fall",
			"Arcane Brilliance",
			"Ritual of Refreshment",
			-- Misc.
			"Invisibility",
			"Dampen Magic",
			"Amplify Magic",
			"Ice Armor",
			"Mage Armor",
			"Molten Armor", 
		};
		if (race == "Human" or race == "Gnome" or race == "Draenei") then
			self.spellList[1]  = "Teleport: Darnassus";
			self.spellList[2]  = "Teleport: Ironforge";
			self.spellList[3]  = "Teleport: Stormwind";
			self.spellList[4]  = "Teleport: Exodar";
			self.spellList[5]  = "Teleport: Theramore";
			self.spellList[7] = "Portal: Darnassus";
			self.spellList[8] = "Portal: Ironforge";
			self.spellList[9] = "Portal: Stormwind";
			self.spellList[10] = "Portal: Exodar";
			self.spellList[11] = "Portal: Theramore";
		end
	elseif (class == "Hunter") then
		self.spellList = {
			-- Aspects
			"Aspect of the Monkey",
			"Aspect of the Hawk",
			"Aspect of the Cheetah",
			"Aspect of the Beast",
			"Aspect of the Wild",
			"",
			-- Stings
			"Serpent Sting",
			"Scorpid Sting",
			"Viper Sting",
			"",
			"",
			"",
			-- Shots
			"Concussive Shot",
			"Arcane Shot",
			"Aimed Shot",
			"Distracting Shot",
			"Multi-Shot",
			"",
			-- Traps
			"Immolation Trap",
			"Freezing Trap",
			"Frost Trap",
			"Explosive Trap",
			"",
			"",
		};
		if (level >= 40) then
			self.spellList[3] = "Aspect of the Pack";
		end
	elseif (class == "Paladin") then
		self.spellList = {
			"Blessing of Might",
			"Blessing of Wisdom",
			"Blessing of Salvation",
			"Blessing of Protection",
			"Seal of Righteousness",
			"Seal of the Crusader",
			"Blessing of Light",
			"Blessing of Kings",
			"Blessing of Sanctuary",
			"Blessing of Freedom",
			"Seal of Light",
			"Seal of Wisdom",
			"Greater Blessing of Might",
			"Greater Blessing of Wisdom",
			"Greater Blessing of Salvation",
			"Blessing of Sacrifice",
			"Seal of Justice",
			"Seal of Vengeance",
			"Greater Blessing of Light",
			"Greater Blessing of Kings",
			"Greater Blessing of Sanctuary",
			"Righteous Fury",
			"Seal of Command",
			"",
		}
		if (race == "Blood Elf") then
			self.spellList[18] = "Seal of Blood"
		end
	end
end

function TGApp:MainOnLoad()

	TGApp:BuildButtons();
	TGApp:SetSpellList();
	TGApp:BuildSpells();

	--DEFAULT_CHAT_FRAME:AddMessage("TotemGarden ("..TOTEMGARDEN_VERSION..") loaded. '/totemgarden' or '/tg' to show commands.");
	TGApp:PrintF("TotemGarden (%s) loaded. '/totemgarden' or '/tg' to show commands.", TGApp.version)
end

-- This function contains some code from TotemBar by Saien
function TGApp:BuildSpells()
	local id = 1;
	local idr1; -- this stores the id of rank 1 of a spell
	local spellName;
	local subSpellName;
	local secondSpellName;
	local secondSubSpellName;
	local idx;
	local taggedSpell;
	spellName, subSpellName = GetSpellName(id,BOOKTYPE_SPELL);
	while (spellName) do
		if (spellName) then
			for idx,taggedSpell in pairs(self.spellList) do
				if (taggedSpell == spellName) then
					idr1 = id
					secondSpellName, secondSubSpellName = GetSpellName(id+1,BOOKTYPE_SPELL);
					while (spellName == secondSpellName) do
						id = id + 1;
						secondSpellName, secondSubSpellName = GetSpellName(id+1,BOOKTYPE_SPELL);
					end
					spellName, subSpellName = GetSpellName(id,BOOKTYPE_SPELL);
					self:SetSpell(id, spellName, subSpellName, idr1 ,idx);
				end
			end
		end
		id = id + 1;
		spellName, subSpellName = GetSpellName(id,BOOKTYPE_SPELL);
	end
	self:HideEmptyButtons();
end

function TGApp:HideEmptyButtons()
	local numButtons = self.buttonsWide * self.buttonsHigh;
	local tg = self.mainframe or getglobal("TotemGarden");

	if (self.inCombat == 1) then
		self:Debug(7,"Not hiding empty buttons, we're in combat.")
		return;
	end

	for i = 1, numButtons do
		local button = getglobal("TotemGardenButton"..i);
		--if ((not button.spellID) and (not TotemGarden_SpellIDList["TotemGardenButton"..i]) ) then
		if (not button.spellID) then
			button:Hide();

			button:SetAttribute("*type*", "");
			button:SetAttribute("*spell*", "")

			button:SetAttribute("delaystate", "0");
			button:SetAttribute("delaytime", "0.1");
			button:SetAttribute("delayhover", "all");
			button:SetAttribute("showstates", "2"); -- never
			button:SetAttribute("newstate", "0");

			button:SetAttribute("anchorchild", tg);
			button:SetAttribute("childstate", "^1");

			--button:SetAttribute("*childraise-OnEnter", true);
			button:SetAttribute("*childstate-OnEnter", "enter");
			button:SetAttribute("*childstate-OnLeave", "leave");

			button:SetAttribute("state", "0");
			tg:SetAttribute("AddChild", button);
		end
	end
	tg:SetAttribute("state", "0");
	self.mainframe = tg
end

--function TotemGarden_SetSpell(spellID, spellName, subSpellName, spellIDrank1, idx)
function TGApp:SetSpell(spellID, spellName, subSpellName, spellIDrank1, idx)
	if (self.inCombat == 1) then
		self:Debug(7,"Not Setting Spell, we're in combat.")
		return;
	end

	subSpellName = subSpellName or "";
	self:Debug(10,"Assigning spell "..spellName.."("..subSpellName..") (id "..spellID..") to TotemGardenButton"..idx)
	local totalButtons = (self.buttonsWide * self.buttonsHigh);
	while (idx > totalButtons) do idx = idx - totalButtons; end
	local button = self.buttons[idx] or getglobal("TotemGardenButton"..idx);
	local tg = self.mainframe or getglobal("TotemGarden")
	if (button and tg) then
		--tg:SetAttribute("addchild", button);
		self.spellIDList[button:GetName()] = spellID;
		button.spellID = spellID;
		button.spellName = spellName;
		button.spellRank = subSpellName;
		button.spellIDrank1 = spellIDrank1;

		local texture = GetSpellTexture(spellID, BOOKTYPE_SPELL);
		local icon = getglobal(button:GetName().."Icon")
		icon:SetTexture(texture);
		icon:Show();

		if GetBuildInfo() == "0.1.0" then
			button:SetAttribute("*type*", "macro");
			button:SetAttribute(      "macrotext", "#showtooltip\n/cast "..spellName..'('..subSpellName..')')
			button:SetAttribute("shift-macrotext", "#showtooltip\n/cast "..spellName..'('..subSpellName..')')
			button:SetAttribute(" ctrl-macrotext", "#showtooltip\n/cast "..spellName..'(Rank 1)')
			button:SetAttribute(  "alt-macrotext", "#showtooltip\n/cast "..spellName..'(Rank 1)')
		else
			button:SetAttribute("*type*", "spell");
			button:SetAttribute(    "spell", spellName..'('..subSpellName..')')
			button:SetAttribute("shift-spell", spellName..'('..subSpellName..')')
			button:SetAttribute(" ctrl-spell", spellName..'(Rank 1)')
			button:SetAttribute(  "alt-spell", spellName..'(Rank 1)')
		end

		-- The buttons are securehoveranchors aswell...
		-- why? because they need to keep resetting the hoverdelay of the main state driver
		button:SetAttribute("delaystate", "0");
		button:SetAttribute("delaytime", "0.1");
		button:SetAttribute("delayhover", "all");
		button:SetAttribute("showstates", "1");
		button:SetAttribute("newstate", "0");

		button:SetAttribute("anchorchild", tg);
		button:SetAttribute("childstate", "^1");

		--button:SetAttribute("*childraise-OnEnter", true);
		button:SetAttribute("*childstate-OnEnter", "enter");
		button:SetAttribute("*childstate-OnLeave", "leave");

		button:SetAttribute("state", "0");

		tg:SetAttribute("AddChild", button);

		self.buttons[idx] = button
		self.mainframe = tg

	else
		self:Debug(3,"Button not found to update "..idx)
	end

end

function TGApp:FrameOnEvent()
	TGApp:MiscOnEvent(event)
end


function TGApp:FrameOnMouseDown()
	TGApp:Debug(9,"OnMouseDown")
	if (IsShiftKeyDown()) then
		this:StartMoving()
	end
end
function TGApp:FrameOnMouseUp()
	TGApp:Debug(9,"OnMouseUp")
	this:StopMovingOrSizing()
end

function TGApp:TitleOnMouseDown()
	TGApp:Debug(9,"OnMouseDown")
	if (IsShiftKeyDown()) then
		self:GetParent():StartMoving()
	end
end
function TGApp:TitleOnMouseUp()
	TGApp:Debug(9,"OnMouseUp")
	self:GetParent():StopMovingOrSizing()
end

local REFRESH_TIME = 0.25;

function TGApp:ButtonOnShow()
	self.refreshtime = 0;
end

function TGApp:ButtonOnUpdate(elapsed)
	-- according to slouken (http://blue.cardplace.com/newcache/us/102909678.htm) this manual call
	-- to UpdateAction might be necessary.
	ActionButton_UpdateAction()

	local remaining = (self.refreshtime or 0) - elapsed;
	if (remaining > 0) then
		self.refreshtime = remaining;
	return;
	end
	self.refreshtime = REFRESH_TIME;
	local button = SecureStateChild_GetEffectiveButton(self);

	local mySpellID = this.spellID;

	if ((not mySpellID) and TGApp.spellIDList[this:GetName()]) then
		mySpellID = TGApp.spellIDList[this:GetName()];
	end

	local cooldown = getglobal(this:GetName().."Cooldown");

	if (mySpellID and mySpellID > 1) then
		local start, duration, enable = GetSpellCooldown(mySpellID, BOOKTYPE_SPELL);
		CooldownFrame_SetTimer(cooldown, start, duration, enable);
		--[[
		local texture = GetSpellTexture(mySpellID, BOOKTYPE_SPELL);
		if (texture) then
			--TotemGarden_Textures[this:GetName()]:SetTexture(texture);
			--TotemGarden_Textures[this:GetName()]:SetAllPoints(this);
			--TotemGarden_Textures[this:GetName()]:Show();

			--local icon = getglobal(this:GetName().."Icon")
			--icon:SetTexture(texture);

			--TGSD("TGBOnUpdate: Set new texture!");
			return;
		end
		]]--
		if (TGApp.inCombat == nil) then
			self:Show();
		end
	else
		cooldown:Hide();
		if (TGApp.inCombat == nil) then
			self:Hide();
		end
		--TGSD("TGBOnUpdate: no SpellID");
	end

	if (TGApp.textures[self:GetName()]) then
		TGApp.textures[self:GetName()]:Hide();
	end
end

function TGApp:ButtonOnEnter()
	TGApp:ButtonSetTooltip()
end

function TGApp:ButtonOnLeave()
	this.updateTooltip = nil;
	GameTooltip:Hide();
end


--function TotemGarden_CreateFrames()
function TGApp:CreateFrames()
	local tg = self.mainframe
	if (not tg) then
		tg = CreateFrame("Frame", "TotemGarden",
		                 UIParent, "SecureStateDriverTemplate");


		if self.sizetestbutton == nil then
			self.sizetestbutton = CreateFrame("CheckButton", "TotemGardenSizeTestButton", tg, "TotemGardenActionButtonTemplate")
		end

		local effectiveWidth = (self.sizetestbutton:GetWidth()*self.buttonsWide) + (self.buttonsWide*3)
		local effectiveHeight = (self.sizetestbutton:GetHeight()*self.buttonsHigh) + (self.buttonsHigh*3)
		tg:SetWidth(effectiveWidth)
		tg:SetHeight(effectiveHeight)

		local titleregion = tg:CreateTitleRegion();
		titleregion:SetAllPoints(tg);
		local tex = tg:CreateTexture();
		tex:SetTexture(0, 0, 0.0, 0.0);
		tex:SetAllPoints(tg);
		tg:SetMovable(true);
		tg:EnableMouse(true);
		tg:SetClampedToScreen(true);
		tg:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
		tg:Show();

		--[[
		tg:RegisterEvent("SPELLS_CHANGED", self:MiscOnEvent);
		tg:RegisterEvent("PLAYER_ENTERING_WORLD", self:MiscOnEvent);
		tg:RegisterEvent("PLAYER_ENTER_COMBAT", TotemGarden_OnEvent);
		tg:RegisterEvent("PLAYER_LEAVE_COMBAT", TotemGarden_OnEvent);
		tg:RegisterEvent("PLAYER_REGEN_ENABLED", TotemGarden_OnEvent);
		tg:RegisterEvent("PLAYER_REGEN_DISABLED", TotemGarden_OnEvent);
		]]--

		tg:SetScript("OnLoad", self.MainOnLoad);
		tg:SetScript("OnEvent", self.FrameOnEvent);
		tg:SetScript("OnMouseDown", self.FrameOnMouseDown);
		tg:SetScript("OnMouseUp", self.FrameOnMouseUp);
		tg.StateChanged = function()
			self:Debug(10,"State Changed to "..arg2);
		end

		tg:SetAttribute("statemap", "0,1");
		tg:SetAttribute("headofspoint", "CENTER");
		tg:SetAttribute("statebindings", "0:^wait;1:top");


		tg:SetAttribute("statemap-anchor-enter", "0:1");
		tg:SetAttribute("statemap-anchor-leave", ";"); -- Non-empty
		tg:SetAttribute("delaystatemap-anchor-leave", "1:0");
		tg:SetAttribute("delaytimemap-anchor-leave", "1:0.1");
		tg:SetAttribute("delayhovermap-anchor-leave", "1:true");

		tg:SetAttribute("state", "0");
		self.mainframe = tg;
		----------------------------------------------
		tgt = CreateFrame("Frame", "TotemGardenTitleText", nil, "SecureActionButtonTemplate,SecureAnchorEnterTemplate");
		tgt:ClearAllPoints();
		tgt:SetPoint("TOPLEFT", tg, "TOPLEFT", 0, 0);
		--tgt:SetPoint("TOPRIGHT", tg, "TOPRIGHT");
		tgt:SetWidth(effectiveWidth);
		tgt:SetHeight(12);
		tgt:SetMovable(true);
		tgt:EnableMouse(true);
		tgt:SetBackdrop( { bgFile = "Interface\Tooltips\UI-Tooltip-Background",
				   edgeFile = "Interface\Tooltips\UI-Tooltip-Border", tile = true, tileSize = 5, edgeSize = 5,
				   insets = { left = 0, right = 0, top = 0, bottom = 0 }
				});


		tgt.texture = tgt:CreateTexture(nil, "BACKGROUND");
		tgt.texture:SetTexture(0.0, 0.0, 0.0, 0.6);
		tgt.texture:SetAllPoints(tgt);
		tgt.title = tgt:CreateFontString(nil, "OVERLAY");
		tgt.title:SetFontObject("GameFontNormal");
		tgt.title:SetAllPoints(tgt);
		tgt.title:SetText("TG "..TGApp.version);


		tgt:SetScript("OnMouseDown", self.TitleOnMouseDown);
		tgt:SetScript("OnMouseUp", self.TitleOnMouseUp);


		tgt:SetAttribute("delaystate", "0");
		tgt:SetAttribute("delaytime", "0.1");
		tgt:SetAttribute("delayhover", "all");
		tgt:SetAttribute("showstates", "1");
		tgt:SetAttribute("newstate", "1");

		tgt:SetAttribute("anchorchild", tg);
		tgt:SetAttribute("childstate", "^1");

		tgt:SetAttribute("shift-childraise-OnEnter", true);
		tgt:SetAttribute("shift-childstate-OnEnter", "enter");
		tgt:SetAttribute("*childstate-OnLeave", "leave");

		tgt:SetAttribute("state", "0");



		self.mainframetitle = tgt;
		tg:SetAttribute("AddChild", tgt);
		----------------------------------------------
		tgh = CreateFrame("Frame", "TotemGardenHidden", nil, "SecureActionButtonTemplate,SecureAnchorEnterTemplate");
		--tgh:SetWidth(self.buttonsWide*40);
		--tgh:SetHeight(self.buttonsHigh*40+tgt:GetHeight());
		local hiddenwidth  = self.db.profile.hiddenframe.width
		if hiddenwidth and hiddenwidth > 0 then
			tgh:SetWidth(hiddenwidth)
		else
			tgh:SetWidth(tg:GetWidth())
		end
		local hiddenheight  = self.db.profile.hiddenframe.height
		if hiddenheight and hiddenheight > 0 then
			tgh:SetHeight(hiddenheight)
		else
			tgh:SetHeight(tg:GetHeight())
		end
		tgh:SetMovable(false)
		tgh:EnableMouse(true)
		tgh:SetFrameStrata("BACKGROUND")
		tgh.bg = tgh:CreateTexture()
		tgh.bg:SetAllPoints(tgh)
		tgh.bg:SetTexture(self.db.profile.hiddenframe.r,self.db.profile.hiddenframe.g,b,self.db.profile.hiddenframe.alpha)
		--tgh:SetBackdrop( { bgFile = "Interface\Tooltips\UI-Tooltip-Background",
		--		   edgeFile = "Interface\Tooltips\UI-Tooltip-Border", tile = true, tileSize = 5, edgeSize = 5,
		--		   insets = { left = 0, right = 0, top = 0, bottom = 0 }
		--		});
		
		tgh:SetPoint("TOPLEFT", tg, "TOPLEFT", 0, 0)
		tgh:SetScript("OnMouseDown", self.FrameOnMouseDown)
		tgh:SetScript("OnMouseUp", self.FrameOnMouseUp)

		tgh:SetAttribute("showstates", "0")

		tgh:SetAttribute("anchorchild", tg)
		tgh:SetAttribute("childstate", "^1")
		tgh:SetAttribute("shift-childraise-OnEnter", true)
		tgh:SetAttribute("shift-childstate-OnEnter", "enter")
		tgh:SetAttribute("*childstate-OnLeave", "leave")

		tgh:SetAttribute("state", "0")

		tg:SetAttribute("AddChild", tgh)
		self.hiddenframe = tgh
		--tg:Show();
	end

	if (self.mainscale > 0) then
		self.mainframe:SetScale(self.mainscale)
	end
	
	self:ApplyHiddenDock()
end

--function TotemGarden_BuildButtons()
function TGApp:BuildButtons()
	if (self.runOnce['BuildButtons']) then
		return
	else
		self.runOnce['BuildButtons'] = true
	end

	self:CreateFrames(); -- make sure the frames exist..

	local width  = self.buttonsWide    -- Width of the bar (in buttons)
	local height = self.buttonsHigh    -- Height of the bar

	local numButtons = width * height

	for i = 1, numButtons do
		-- These values are used to position the buttons
		local relativeTo, relativePoint
		local xOfs, yOfs = 0, 0

		-- Set up the various positioning values based on which button we're on
		if i == 1 then
			--[[
			First button: anchored to the top left of the state header. As
			mentioned in the XML, the "drag box" will be to the top left of this
			button.
			]]
			relativeTo = self.mainframetitle
			relativePoint = "BOTTOMLEFT"
		elseif mod(i - 1, height) == 0 then
			-- First button in the column: anchored to the button left of it
			relativeTo = getglobal("TotemGardenButton"..(i - height))
			relativePoint = "TOPRIGHT"
			xOfs = 4
		else
			-- All other buttons: anchored to the button to its left
			relativeTo = getglobal("TotemGardenButton"..(i - 1))
			relativePoint = "BOTTOMLEFT"
			yOfs = -4
		end

		-- Create and position the button
		self.buttons[i] = CreateFrame("CheckButton", "TotemGardenButton"..i, self.mainframe, "TotemGardenActionButtonTemplate")
		--TotemGarden_Buttons[i]:SetFrameStrata("HIGH");
		--TotemGarden_Buttons[i]:Show();

		self.buttons[i].spellID = nil;
		self.buttons[i].spellName = nil;

		--local t = TotemGarden_Buttons[i]:CreateTexture(nil, "OVERLAY");
		--t:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Factions.blp");
		--t:SetAllPoints(TotemGarden_Buttons[i]);
		--TotemGarden_Textures[TotemGarden_Buttons[i]:GetName()] = t;


		self.buttons[i]:SetPoint("TOPLEFT", relativeTo, relativePoint, xOfs, yOfs)

		self.buttons[i]:SetScript("OnShow", self.ButtonOnShow);
		self.buttons[i]:SetScript("OnUpdate", self.ButtonOnUpdate);

		if GetBuildInfo() == "0.1.0" then
			self.buttons[i]:HookScript("OnEnter", TGApp.ButtonOnEnter);
			self.buttons[i]:HookScript("OnLeave", TGApp.ButtonOnLeave);
		end

		--if (TotemGarden_Buttons[i]:HasScript("OnAttributeChanged")) then
		--	TotemGarden_Buttons[i]:SetScript("OnAttributeChanged", childOnShow);
		--end
	end

	--[[
	local tg = getglobal("TotemGarden");
	local tgh = getglobal("TotemGardenHidden");
	local tgt = getglobal("TotemGardenTitleText");
	if (tg and tgh and tgt) then
		TGSD("Resizing frame..");
		tg:SetWidth(width*TotemGarden_Buttons[1]:GetWidth());
		tg:SetHeight(height*TotemGarden_Buttons[1]:GetHeight());
		tgh:ClearAllPoints();
		tgh:SetAllPoints(tg);


	end
	]]--


end


function TGApp:MiscOnEvent(event)
	event = event or arg1
	if (event == "SPELLS_CHANGED") then
		--TotemGarden_BuildSpells();
		--TotemGarden_BuildButtons();
	--elseif (event == "PLAYER_ENTER_COMBAT") then
	--	self:CombatLockdown()
	--elseif (event == "PLAYER_LEAVE_COMBAT") then
	--	self:CombatUnlock()
	elseif (event == "PLAYER_REGEN_DISABLED") then
		self:CombatLockdown()
	elseif (event == "PLAYER_REGEN_ENABLED") then
		self:CombatUnlock()
	elseif (event == "PLAYER_ENTERING_WORLD") then

		self:BuildButtons();
		self:SetSpellList();
		self:BuildSpells();

	end
end

--[[
function TGApp:OnStateChanged(newstate)
	TGSD("State changed to "..newstate);
	TotemGardenTitleText:SetText(TotemGarden:GetAttribute("state"));

end
]]--


--[[
function TGApp:ButtonUpdateCooldown()
	local cooldown = getglobal(this:GetName().."Cooldown");
	if (this.spellID) then
		local start, duration, enable = GetSpellCooldown (this.spellID, BOOKTYPE_SPELL);
		CooldownFrame_SetTimer(cooldown, start, duration, enable);
	else
		cooldown:Hide();
	end
end
]]--

function TGApp:ButtonSetTooltip()
	--if TGApp.inCombat == 1 then
	--	return
	--end
	if (this.spellID) then
		local spellName, subSpellName = GetSpellName(this.spellID,BOOKTYPE_SPELL);
		if ( GetCVar("UberTooltips") == "1" ) then
			GameTooltip_SetDefaultAnchor(GameTooltip, this);
			GameTooltip:SetSpell(this.spellID, BOOKTYPE_SPELL);
			--if (subSpellName and subSpellName ~= "") then
			--	GameTooltipTextRight1:SetText("("..subSpellName..")");
			--end
		else
			GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
			local txt;
			if (subSpellName and subSpellName ~= "") then
				txt = spellName.." ("..subSpellName..")";
			else
				txt = spellName;
			end
			GameTooltip:SetText(txt);
		end
	end
end

--[[
function TGApp:ButtonUpdate()
	if (this.spellID) then
		local num = this:GetID();
		this:Show();
		TotemGarden_Button_UpdateCooldown();

	else
		this:Hide();
	end
end
]]--

function TGApp:ButtonOnDrag()
	if (IsControlKeyDown()) then
		--TGSD("Pickup alt");
		if (this.spellIDrank1) then
			ClearCursor();
			PickupSpell(this.spellIDrank1, BOOKTYPE_SPELL);
			return;
		else
			return;
		end
	end
	if (this.spellID) then
		--TGSD("Pickup normal");
		ClearCursor();
		PickupSpell(this.spellID, BOOKTYPE_SPELL);
	else
		return;
	end
end


